#include "paladin.h"

bool Paladin::isInit = false;
const float Paladin::camX = 0;
const float Paladin::camY = 9;
const float Paladin::camZ = -20;

textureFile Paladin::chassis;
textureFile Paladin::tube;
textureFile Paladin::track;

Paladin::Paladin()
{
   camera = new Camera();
}

void Paladin::Draw(float elevation, float deflection, bool needed)
{
   //    If this is the first draw, initalize everything.
   if (!isInit) 
   {
      Init();
      isInit = true;
   }
   
   elev = elevation;
   defl = deflection;
   
   UpdateCamera(needed);
   
   glPushMatrix();
   {
      // Sets the specular and shininess of the object.
      GLfloat spec[4] = {1.0,1.0,1.0,1.0};
      glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
      glMateriali(GL_FRONT, GL_SHININESS, 128);
      glMaterialfv(GL_FRONT, GL_AMBIENT, spec);
      glMaterialfv(GL_FRONT, GL_DIFFUSE, spec);
   }
   glPopMatrix();
   
   //    Draw one set of tracks.
   glPushMatrix();
   {
      glRotatef(-90, 0, 1, 0);
      glTranslatef(1,0,-3);
      DrawTracks();
   }
   glPopMatrix();
   //    Draw the other set of tracks.
   glPushMatrix();
   {
      glRotatef(-90, 0, 1, 0);
      glTranslatef(1, 0, 3);
      glScalef(1,1,-1);
      DrawTracks();
   }
   glPopMatrix();
   
   //    Draw the body of the Paladin.
   glPushMatrix();
   {
      glTranslatef(0, 1.0 ,0);
      DrawChassis();
   }
   glPopMatrix();
   
   //    Draw the turret and barrel.
   glPushMatrix();
   {
      glDisable(GL_CULL_FACE);
      glTranslatef(0,3.5,-2.2);
      glRotatef(deflection, 0,1,0);
      DrawTurret();
      
      DrawTube();
   }
   glPopMatrix();
}

void Paladin::DrawChassis()
{
   // Make sure that the texture isn't shaded.
   //glColor3f(1,1,1);
   glBindTexture(GL_TEXTURE_2D, chassis.id);
   glEnable(GL_TEXTURE_2D);
   
   // Holds the normal vector
   M3DVector3f vNormal;
   
   glBegin(GL_QUADS);
   
   //    Bottom
   glTexCoord2f(0.0f, 0.1f);
   glNormal3f(0.0f, 1.0f, 0.0f);
   glVertex3f(-C_INSIDE_W, 0, +C_BASE_L);
   glTexCoord2f(0.1f, 0.0f);
   glVertex3f(+C_INSIDE_W, 0, +C_BASE_L);
   glTexCoord2f(0.1f, 0.1f);
   glVertex3f(+C_INSIDE_W, 0, -C_BASE_L);
   glTexCoord2f(0.1f, 0.0f);
   glVertex3f(-C_INSIDE_W, 0, -C_BASE_L);
   
   //    Top
   {
      M3DVector3f vPoints[3] = {{ +C_OUTSIDE_W, +C_TOP_H, +C_TOP_L },
         { -C_OUTSIDE_W, +C_TOP_H, +C_TOP_L },
         { -C_OUTSIDE_W, +C_TOP_H, -C_BASE_L} };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.749f, 0.731f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(1.0f, 0.731f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.749f, 1.0f);
      glVertex3f(+C_OUTSIDE_W, +C_TOP_H, -C_BASE_L);
   }
   
   //    Front Slanting
   {
      M3DVector3f vPoints[3] = {{ +C_OUTSIDE_W, +C_MID2_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_MID2_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_TOP_H,  +C_TOP_L} };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.749f, 0.650f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.978f, 0.650f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.000f, 0.731f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.748f, 0.731f);
      glVertex3f(+C_OUTSIDE_W, +C_TOP_H,  +C_TOP_L);
   }
   
   //    Front Flat
   {
      M3DVector3f vPoints[3] = {{ +C_OUTSIDE_W, +C_MID1_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_MID1_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_MID2_H, +C_BASE_L} };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.384f, 0.403f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.158f, 0.403f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.158f, 0.365f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.384f, 0.365f);;
      glVertex3f(+C_OUTSIDE_W, +C_MID2_H, +C_BASE_L);
   }
   
   //    Front Bottom
   {
      M3DVector3f vPoints[3] = {{ +C_INSIDE_W, 0, +C_BASE_L },
         { -C_INSIDE_W, 0, +C_BASE_L },
         { -C_INSIDE_W, +C_MID1_H, +C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.190f, 0.425f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.351f, 0.425f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.351f, 0.403f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.190f, 0.403f);
      glVertex3f(+C_INSIDE_W, +C_MID1_H, +C_BASE_L);
   }
   
   //    Back Top
   {
      M3DVector3f vPoints[3] = {{ -C_OUTSIDE_W, +C_MID1_H, -C_BASE_L },
         { +C_OUTSIDE_W, +C_MID1_H, -C_BASE_L },
         { +C_OUTSIDE_W, +C_TOP_H,  -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.557f, 0.174f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.843f, 0.177f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.843f, 0.124f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.557f, 0.121f);
      glVertex3f(-C_OUTSIDE_W, +C_TOP_H,  -C_BASE_L);
   }
   
   //    Back Bottom
   {
      M3DVector3f vPoints[3] = {{ -C_INSIDE_W, 0, -C_BASE_L },
         { +C_INSIDE_W, 0, -C_BASE_L },
         { +C_INSIDE_W, +C_MID1_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.5965f, 0.229f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.804f, 0.229f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.804f, 0.177f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.5965f, 0.174f);
      glVertex3f(-C_INSIDE_W, +C_MID1_H, -C_BASE_L);
   }
   
   //    Right Side Top
   {
      M3DVector3f vPoints[3] = {{ +C_OUTSIDE_W, +C_MID2_H, +C_BASE_L },
         { +C_OUTSIDE_W, +C_MID2_H, -C_BASE_L },
         { +C_OUTSIDE_W, +C_TOP_H,  -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.063f, .133f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.447f, .133f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.447f, 0.107f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.144f, 0.107f);
      glVertex3f(+C_OUTSIDE_W, +C_TOP_H,  +C_TOP_L);
   }
   
   //    Right Side Middle
   {
      M3DVector3f vPoints[3] = {{ +C_OUTSIDE_W, +C_MID1_H, +C_BASE_L },
         { +C_OUTSIDE_W, +C_MID1_H, -C_BASE_L },
         { +C_OUTSIDE_W, +C_MID2_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.063f, 0.153f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.447f, 0.153f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.447f, 0.133f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.063f, 0.133f);
      glVertex3f(+C_OUTSIDE_W, +C_MID2_H, +C_BASE_L);
   }
   
   //    Right Side Track Ceiling
   {
      M3DVector3f vPoints[3] = {{ +C_INSIDE_W, +C_MID1_H,  +C_BASE_L },
         { +C_INSIDE_W, +C_MID1_H,  -C_BASE_L },
         { +C_OUTSIDE_W, +C_MID1_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);      
      glTexCoord2f(0.0f, 0.5f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(1.0f, 0.5f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.0f, 1.0f);
      glVertex3f(+C_OUTSIDE_W, +C_MID1_H, +C_BASE_L);
   }
   
   //    Right Side Track Wall
   {
      M3DVector3f vPoints[3] = {{ +C_INSIDE_W, 0, -C_BASE_L },
         { +C_INSIDE_W, 0, +C_BASE_L },
         { +C_INSIDE_W, +C_MID1_H, +C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);  
      glTexCoord2f(0.0f, 0.5f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(1.0f, 0.5f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.0f, 1.0f);
      glVertex3f(+C_INSIDE_W, +C_MID1_H, -C_BASE_L);
   }
   
   //    Left Side Top
   {
      M3DVector3f vPoints[3] = {{ -C_OUTSIDE_W, +C_MID2_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_MID2_H, -C_BASE_L },
         { -C_OUTSIDE_W, +C_TOP_H,  -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);  
      glTexCoord2f(0.063f, .133f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.447f, .133f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.447f, 0.107f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.144f, 0.107f);
      glVertex3f(-C_OUTSIDE_W, +C_TOP_H,  +C_TOP_L);
   }
   
   //    Left Side Middle
   {
      M3DVector3f vPoints[3] = {{ -C_OUTSIDE_W, +C_MID1_H, +C_BASE_L },
         { -C_OUTSIDE_W, +C_MID1_H, -C_BASE_L },
         { -C_OUTSIDE_W, +C_MID2_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal); 
      glTexCoord2f(0.063f, 0.153f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.447f, 0.153f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.447f, 0.133f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.063f, 0.133f);
      glVertex3f(-C_OUTSIDE_W, +C_MID2_H, +C_BASE_L);
   }
   
   //    Left Side Track Ceiling
   {
      M3DVector3f vPoints[3] = {{ -C_INSIDE_W, +C_MID1_H,  +C_BASE_L },
         { -C_INSIDE_W, +C_MID1_H,  -C_BASE_L },
         { -C_OUTSIDE_W, +C_MID1_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal); 
      glTexCoord2f(0.0f, 0.5f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(1.0f, 0.5f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.0f, 1.0f);
      glVertex3f(-C_OUTSIDE_W, +C_MID1_H, +C_BASE_L);
   }
   
   //    Left Side Track Wall
   {
      M3DVector3f vPoints[3] = {{ -C_INSIDE_W, 0, +C_BASE_L },
         { -C_INSIDE_W, 0, -C_BASE_L },
         { -C_INSIDE_W, +C_MID1_H, -C_BASE_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal); 
      glTexCoord2f(0.0f, 0.5f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(1.0f, 0.5f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(1.0f, 1.0f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.0f, 1.0f);
      glVertex3f(-C_INSIDE_W, +C_MID1_H, +C_BASE_L);
   }
   
   glEnd();
   glDisable(GL_TEXTURE_2D);
}

void Paladin::DrawTurret()
{
   //glColor3f(1,1,1); // Ensures no extra shading from previous draw code.
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, chassis.id);
   
   // holds the vector normal
   M3DVector3f vNormal;
   
   glBegin(GL_QUADS);
   
   //    Top 715 
   glTexCoord2f(0.141f, 0.972f);
   glVertex3f(+T_TOP_W, +T_HEIGHT, +T_TOP_L);
   glTexCoord2f(0.732f, 1.0f);
   glVertex3f(+T_TOP_W, +T_HEIGHT, -T_TOP_L);
   glTexCoord2f(0.715f, 0.478f);
   glVertex3f(-T_TOP_W, +T_HEIGHT, -T_TOP_L);
   glTexCoord2f(0.157f, 0.527f);
   glVertex3f(-T_TOP_W, +T_HEIGHT, +T_TOP_L);
   
   //    Bottom
   glTexCoord2f(0.0f, 0.5f);
   glVertex3f(-T_BOTTOM_W, 0, +T_BOTTOM_L);
   glTexCoord2f(1.0f, 0.5f);
   glVertex3f(+T_BOTTOM_W, 0, +T_BOTTOM_L);
   glTexCoord2f(1.0f, 1.0f);
   glVertex3f(+T_BOTTOM_W, 0, +T_BOTTOM_L);
   glTexCoord2f(0.0f, 1.0f);
   glVertex3f(-T_BOTTOM_W, 0, +T_BOTTOM_L);
   
   //    Front
   glTexCoord2f(0.389f, 0.336f);
   glVertex3f(+T_BOTTOM_W, 0,        +T_BOTTOM_L);
   glTexCoord2f(0.164f, 0.336f);
   glVertex3f(-T_BOTTOM_W, 0,        +T_BOTTOM_L);
   glTexCoord2f(0.185f, 0.273f);
   glVertex3f(-T_TOP_W,    T_HEIGHT, +T_TOP_L);
   glTexCoord2f(0.368f, 0.278f);
   glVertex3f(+T_TOP_W,    T_HEIGHT, +T_TOP_L);
   
   //    Back
   glTexCoord2f(0.840f, 0.117f);
   glVertex3f(-T_BOTTOM_W, 0,        -T_BOTTOM_L);
   glTexCoord2f(0.564f, 0.117f);
   glVertex3f(+T_BOTTOM_W, 0,        -T_BOTTOM_L);
   glTexCoord2f(0.589f, 0.057f);
   glVertex3f(+T_TOP_W,    T_HEIGHT, -T_TOP_L);
   glTexCoord2f(0.818f, 0.057f);
   glVertex3f(-T_TOP_W,    T_HEIGHT, -T_TOP_L);
   
   //    Right Side
   {
      M3DVector3f vPoints[3] = {{ -T_BOTTOM_W, 0, +T_BOTTOM_L },
         { -T_BOTTOM_W, 0, -T_BOTTOM_L },
         { -T_TOP_W,    T_HEIGHT, -T_TOP_L } };
      
      m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
      glNormal3fv(vNormal);
      glTexCoord2f(0.445f, 0.362f);
      glVertex3fv(vPoints[0]);
      glTexCoord2f(0.740f, 0.355f);
      glVertex3fv(vPoints[1]);
      glTexCoord2f(0.735f, 0.284f);
      glVertex3fv(vPoints[2]);
      glTexCoord2f(0.450f, 0.257f);
      glVertex3f(-T_TOP_W,    T_HEIGHT, +T_TOP_L);
   }
   
   //    Left Side
   glTexCoord2f(0.223f, 0.104f);
   glVertex3f(+T_BOTTOM_W, 0,        -T_BOTTOM_L);
   glTexCoord2f(0.444f, 0.104f);
   glVertex3f(+T_BOTTOM_W, 0,        +T_BOTTOM_L);
   glTexCoord2f(0.444f, 0.045f);
   glVertex3f(+T_TOP_W,    T_HEIGHT, +T_TOP_L);
   glTexCoord2f(0.246f, 0.045f);
   glVertex3f(+T_TOP_W,    T_HEIGHT, -T_TOP_L);
   
   glEnd();
   glDisable(GL_TEXTURE_2D);
}

void Paladin::DrawTube()
{
   glPushAttrib(GL_POLYGON_BIT);
      glFrontFace(GL_CCW); 
   
   //glColor3f(1,1,1); // Ensure no shading on texture.
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, tube.id);
   
   GLUquadricObj *quadric = gluNewQuadric();
   gluQuadricTexture(quadric, GL_TRUE);
   
   glPushMatrix();
   {
      glEnable(GL_COLOR_MATERIAL);
      // Make the tube rotate around the intersection rather than the tip.
      glTranslatef(0, -1, 3.25);
      glRotatef(elev, 1,0,0);
      glTranslatef(0, 1.51, -3.25);
      
      // Make's it look like a pipe instead of a cylinder.
      gluCylinder(quadric, 0.5, 0.4, 10.324, 32, 1);
      glColor3fv(Black);
      gluCylinder(gluNewQuadric(), .3, .3, 10.324, 32, 1);
      
      glTranslatef(0,0, 4.5f);
      gluDisk(gluNewQuadric(), 0, .4, 32, 1);
      glTranslatef(0,0, 5.824);
      gluDisk(gluNewQuadric(), .3, .4, 32, 1);
      glDisable(GL_TEXTURE_2D);
      glDisable(GL_COLOR_MATERIAL);
   }
   glPopMatrix();

   glPopAttrib();
}

void Paladin::DrawTracks()
{
   //    Road Wheels
   glPushMatrix();
   glTranslatef(0, 1.0, 0);
   glPushMatrix();
   glTranslatef(4.235, 0, -.2);
   float adjust = 1.412;
   for (int i = 0; i < 7; ++i)
   {
      glTranslatef(-adjust, 0,0);
      drawWheel();
   }
   glPopMatrix();
   
   glPushMatrix();
   glScalef(.6, .6, 1);
   
   glTranslatef(7, .9, -.2);
   drawWheel();
   
   glTranslatef(-18.5, 0, -.2);
   drawWheel();
   glPopMatrix();
   glPopMatrix();
   
   //    Track Pads
   glPushMatrix();
   //    On-the-ground
   glTranslatef(-6, 0, 0);
   glBindTexture(GL_TEXTURE_2D, track.id);
   glEnable(GL_TEXTURE_2D);
   for (int i = 0; i < 16; ++i)
   {
      glTranslatef(.525,0,0);
      drawPad();
   }
   glPopMatrix();
   
   glPushMatrix();
   //    Wrapping around front wheel
   glTranslatef(3.3,0,0);
   glRotatef(15.0f, 0, 0, 1);
   glTranslatef(-.25,0.1,0);
   drawPad();
   
   glRotatef(20.0f, 0, 0, 1);
   glTranslatef(0,-.1,0);
   for (int i = 0; i < 3; ++i)
   {
      glTranslatef(.525,0,0);
      drawPad();
   }
   
   glRotatef(30.0f, 0, 0, 1);
   glTranslatef(.55,-0.2,0);
   drawPad();
   
   glRotatef(60.0f, 0,0,1);
   glTranslatef(.525,-.3,0);
   drawPad();
   
   glRotatef(60.0f, 0,0,1);
   glTranslatef(0.5,-0.4,0);
   drawPad();
   
   glRotatef(10, 0,0,1);
   glTranslatef(0.5,0,0);
   drawPad();
   
   glRotatef(5, 0,0,-1);
   glTranslatef(0.5,.05,0);
   drawPad();
   
   glRotatef(10, 0,0,-1);
   for (int i = 0; i < 17; ++i)
   {
      glTranslatef(.525,0,0);
      drawPad();
   }
   
   //    Wrapping around the back wheel
   glRotatef(15, 0,0,-1);
   glTranslatef(.525,0.1,0);
   drawPad();
   
   glRotatef(5, 0,0,-1);
   glTranslatef(.525,0,0);
   drawPad();
   
   glRotatef(45, 0,0,1);
   glTranslatef(.525,-0.2,0);
   drawPad();
   
   glRotatef(45, 0,0,1);
   glTranslatef(.525,-0.2,0);
   drawPad();
   
   glRotatef(60, 0,0,1);
   glTranslatef(.525,-0.3,0);
   drawPad();
   
   glRotatef(20, 0,0,1);
   for (int i = 0; i < 3; ++i)
   {
      glTranslatef(.525,0,0);
      drawPad();
   }
   
   glRotatef(12, 0,0,1);
   glTranslatef(.525,-0.1,0);
   drawPad();
   glPopMatrix();
}

void Paladin::drawWheel()
{
   glPushMatrix();
   {
      glEnable(GL_COLOR_MATERIAL);
      //    Sets all the wheels to the right color.
      glColor3fv(Black);
      
      //    Creates the cylinder quadrics so I can set the
      //    normal orientation.
      GLUquadric* outRing = gluNewQuadric();
      GLUquadric* inRing = gluNewQuadric();
      GLUquadric* hubcab = gluNewQuadric();
      
      //    Set the normal orientation.
      gluQuadricOrientation(outRing, GLU_OUTSIDE);
      gluQuadricOrientation(inRing,  GLU_INSIDE);
      gluQuadricOrientation(hubcab,  GLU_OUTSIDE);
      
      //    Front Outer Ring
      gluDisk(gluNewQuadric(), .529, .735, 64, 1);
      
      //    Outside Cylinder
      gluCylinder(outRing, .735, .735, .618, 64, 1);
      
      //    Inside Cylinder
      gluCylinder(inRing, .529, .529, .294, 64, 1);
      
      //    Inside Face
      glPushMatrix();
      glTranslatef(0,0,.294);
      glColor3f(OliveDrab[r] * .5, OliveDrab[g] * .5, OliveDrab[b] * .5);
      gluDisk(gluNewQuadric(), 0, .529, 64, 1);
      glPopMatrix();
      
      //    Hubcab
      gluCylinder(hubcab, .294, .294, .3, 64, 1);
      gluDisk(gluNewQuadric(), 0, .294, 64, 1);
   }
   glDisable(GL_COLOR_MATERIAL);
   glPopMatrix();
}

/*
 *    Draws a single track pad.
 */
void Paladin::drawPad()
{
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, track.id);
   
   glBegin(GL_QUADS);
   //    Bottom
   glTexCoord2f(1.0f, 0.396f);   glVertex3f(-0.25f,  0.0f, -0.309f);
   glTexCoord2f(1.0f, 0.0f);     glVertex3f(0.25f, 0.0f, -0.309f);
   glTexCoord2f(0.0f, 0.0f);     glVertex3f(0.25f, 0.0f, 0.309f);
   glTexCoord2f(0.0f, 0.396f);   glVertex3f(-0.25f,  0.0f, 0.309f);
   //    Front
   glTexCoord2f(0.0f, 0.0f); glVertex3f(0.25f, 0.0f, -0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(0.25f, 0.2f, -0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(0.25f, 0.2f, 0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(0.25f, 0.0f, 0.309f);
   //    Top
   glTexCoord2f(0.772f, 0.940f); glVertex3f(0.25f, 0.2f, -0.309f);
   glTexCoord2f(0.772f, 0.632f); glVertex3f(-0.25f, 0.2f, -0.309f);
   glTexCoord2f(0.0f,   0.632f); glVertex3f(-0.25f, 0.2f, 0.309f);
   glTexCoord2f(0.0f,   0.940f); glVertex3f(0.25f, 0.2f, 0.309f);
   //    Back
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.25f, 0.0f, 0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.25f, 0.2f, 0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.25f, 0.2f, -0.309f);
   glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.25f, 0.0f, -0.309f);
   //    Outside
   glTexCoord2f(0.458f, 0.398f); glVertex3f(0.25f, 0.0f, -0.309f);
   glTexCoord2f(0.0f, 0.398f); glVertex3f(-0.25f, 0.0f, -0.309f);
   glTexCoord2f(0.0f, 0.618f); glVertex3f(-0.25f, 0.2f, -0.309f);
   glTexCoord2f(0.458f, 0.618f); glVertex3f(0.25f, 0.2f, -0.309f);
   //    Inside
   glTexCoord2f(0.458f, 0.398f); glVertex3f(-0.25f, 0.0f, 0.309f);
   glTexCoord2f(0.0f, 0.398f); glVertex3f(0.25f, 0.0f, 0.309f);
   glTexCoord2f(0.0f, 0.618f); glVertex3f(0.25f, 0.2f, 0.309f);
   glTexCoord2f(0.458f, 0.618f); glVertex3f(-0.25f, 0.2f, 0.309f);
   glEnd();
   glBindTexture(GL_TEXTURE_2D, 0);
   glDisable(GL_TEXTURE_2D);
}


/*
 *    Sets, loads, and makes textures for the Paladin.
 */
void Paladin::Init()
{
   if (chassis.filename == "")
   {
      chassis.filename = "resources/paladin.raw";
      chassis.height = chassis.width = 512;
      loadRawImage(chassis);
      makeTexture(chassis);
   }
   if (tube.filename == "" && tube.texture == NULL)
   {
      tube.filename = "resources/tube.raw";
      tube.width = tube.height = 512;
      loadRawImage(tube);
      makeTexture(tube);
   }
   if (track.filename == "" && track.texture == NULL)
   {
      track.filename = "resources/track.raw";
      track.width = track.height = 565;
      loadRawImage(track);
      makeTexture(track);
   }   
}

void Paladin::UpdateCamera(bool needed)
{
   if (!needed)
      return;

   float angle[3], newLoc[3], newDir[3];
   
   //    Calculate the components of the elevation and deflection.
   angle[x] = sin(defl * M3D_PI_DIV_180);
   angle[y] = sin(-elev * M3D_PI_DIV_180);
   angle[z] = cos(defl * M3D_PI_DIV_180);
   
   //    Calculate where the camera will move to.
   newLoc[x] = -2 * 10.324 * angle[x];
   newLoc[y] = camY - angle[y] * camY;
   newLoc[z] = -2 * 10.324 * angle[z];
   
   //    Calculate the direction the camera will be pointing based on
   //    it's new location.
   newDir[x] = 10.324 * angle[x];
   newDir[y] = camY - newLoc[y] * angle[y];
   newDir[z] = 10.324 * angle[z] - 2.2;
   
   camera->UpdateLocation(newLoc[x], newLoc[y], newLoc[z]);
   camera->UpdateDirection(newDir[x], newDir[y], newDir[z]);
}

void Paladin::UpdateCamera(float& elevation, float& deflection)
{
   if (elevation >= 90) elevation = 90;
   else if (elevation <= -60) elevation = -60;
   if (deflection > 360) deflection -= 360;
   else if (deflection < 0) deflection = 360 + deflection;

   float angle[3], newLoc[3], newDir[3];
   
   //    Calculate the components of the elevation and deflection.
   angle[x] = sin(deflection * M3D_PI_DIV_180);
   angle[y] = sin(-elevation * M3D_PI_DIV_180);
   angle[z] = cos(deflection * M3D_PI_DIV_180);
   
   //    Calculate where the camera will move to.
   newLoc[x] = -2 * 10.324 * angle[x];
   newLoc[y] = camY - angle[y] * camY;
   newLoc[z] = -2 * 10.324 * angle[z];
   
   //    Calculate the direction the camera will be pointing based on
   //    it's new location.
   newDir[x] = 0;
   newDir[y] = 6;
   newDir[z] = 0;
   
   camera->UpdateLocation(newLoc[x], newLoc[y], newLoc[z]);
   camera->UpdateDirection(newDir[x], newDir[y], newDir[z]);
}
